package com.lujianfei.filetransfer

import android.content.ContentResolver
import android.content.Context
import android.net.Uri
import android.provider.OpenableColumns
import android.util.Log
import androidx.core.database.getStringOrNull
import androidx.core.net.toFile
import java.io.InputStream
import java.lang.Exception
import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetAddress
import java.util.concurrent.Executors


/**
 * Author: lujianfei
 * Date: 2023/11/2 11:37
 * Description: 文件传输管理器
 */

class FileTransferManager private constructor() {

    companion object {
        val instance by lazy { FileTransferManager() }
    }

    private val listeners = arrayListOf<OnFileTransferCallBack>()
    // 服务端
    private var serverRunning = false
    private val threadPool by lazy { Executors.newCachedThreadPool() }

    fun addListener(listener:OnFileTransferCallBack) {
        listeners.add(listener)
    }

    fun removeListener(listener:OnFileTransferCallBack) {
        listeners.remove(listener)
    }
    fun startFileServer(port:Int) {
        serverRunning = true
        if (!threadPool.isShutdown) {
            threadPool.submit {
                DatagramSocket(port).use { socket->
                    // 准备一个缓冲区
                    val buffer = ByteArray(1024)
                    // 循环接收数据报包
                    while (serverRunning) {
                        // 创建数据报包对象, 用来接收数据
                        val packet = DatagramPacket(buffer, buffer.size)
                        // 接收数据报包
                        socket.receive(packet)
                        // 接收数据长度
                        val len = packet.length
                        if (len > 0) {
                            MessageParser.parse(
                                buffer = buffer.toMutableList().subList(0, len),
                                onFileName = { fileName->
                                    notifyMessage(callback = {
                                        it.onFileName(fileName = fileName, address = socket.inetAddress.toString())
                                    })
                                })
                        }
                    }
                }
            }
        }
    }

    fun notifyMessage(callback:(OnFileTransferCallBack)->Unit) {
        val iterator = listeners.iterator()
        while (iterator.hasNext()) {
            callback.invoke(iterator.next())
        }
    }
    fun sendFile(context: Context, uri:Uri, address:String, port: Int) {
        var inputStream:InputStream?= null
        try {
            inputStream = context.contentResolver.openInputStream(uri)
            val totalSize = inputStream?.available()
            if (!threadPool.isShutdown) {
                threadPool.submit {
                    DatagramSocket().use { socket->
                        // 创建远程主机IP地址对象
                        val inetAddress = InetAddress.getByName(address)

                        // 发送文件名
                        val messageFileName = MessageBuilder.buildFileMessage(context, uri)
                        val packet = DatagramPacket(messageFileName.toByteArray(), messageFileName.size, inetAddress, port)
                        socket.send(packet)
                    }
                }
            }
        } catch (e:Exception) {

        } finally {
            inputStream?.close()
        }
    }

    fun release() {
        listeners.clear()
        serverRunning = false
        threadPool.shutdownNow()
    }
    ////////////////////报文格式///////////////////
    // 报头 (2字节)  类型（1字节） 长度（2字节） 数据（） 报尾（2字节）
    // 0xAB 0xAB  | 0x01 (文件名) | 0xff 0xff | xxxxx | 0xBA 0xBA
    //
}

interface OnFileTransferCallBack {
    fun onFileName(fileName:String, address: String)
}

object MessageFlagByte {
    val HeadFlag = listOf(0xAB.toByte(),0xAB.toByte())
    val TailFlag = listOf(0xBA.toByte(),0xBA.toByte())
}

object MessageFlag {
    const val HeadFlag = 1
    const val TailFlag = 2
    const val FileNameFlag = 3
    const val FileNameLenFlag = 4
    const val FileNameEndFlag = 5
}

object MessageFlagType {
    val FileName = listOf(0x01.toByte())
}

object MessageBuilder {
    fun buildFileMessage(context: Context, uri: Uri):List<Byte> {
        val fileName = when (uri.scheme) {
            ContentResolver.SCHEME_FILE-> {
                uri.toFile().name?:""
            }
            ContentResolver.SCHEME_CONTENT-> {
                val cursor = context.contentResolver.query(uri, null, null, null, null, null)
                cursor?.let {
                    it.moveToFirst()
                    val displayName = it.getStringOrNull(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
                    cursor.close()
                    displayName
                }
            }
            else-> ""
        }
        val nameByteArray = fileName?.toByteArray(charset = Charsets.UTF_8)
        val dataList = arrayListOf<Byte>()
        dataList.addAll(MessageFlagByte.HeadFlag)
        dataList.addAll(MessageFlagType.FileName)
        dataList.addAll(messageLenIntToByte(nameByteArray?.size?:0))
        dataList.addAll(nameByteArray?.toList()?: emptyList())
        dataList.addAll(MessageFlagByte.TailFlag)
        log("buildFileMessage name:$fileName")
        return dataList
    }
}
object MessageParser {
    fun parse(buffer:List<Byte>, onFileName:(String)->Unit) {
        val parseList = arrayListOf<Byte>()
        var lastFlag = 0
        var fileNameLen = 0
        var valid = false
        var fileName = ""
        for (idx in buffer.indices) {
            parseList.add(buffer[idx])
            if (parseList == MessageFlagByte.HeadFlag) { // 解析报头
                lastFlag = MessageFlag.HeadFlag
                parseList.clear()
                continue
            }

            if (lastFlag == MessageFlag.HeadFlag) { // 解析类型
                if (parseList == MessageFlagType.FileName) {
                    lastFlag = MessageFlag.FileNameFlag
                    parseList.clear()
                    continue
                }
            }

            if (lastFlag == MessageFlag.FileNameFlag) { // 解析文件名长度
                if (parseList.size == 2) {
                    lastFlag = MessageFlag.FileNameLenFlag
                    fileNameLen = messageLenByteToInt(parseList)
                    parseList.clear()
                    continue
                }
            }

            if (lastFlag == MessageFlag.FileNameLenFlag) {  // 解析文件名
                if (parseList.size == fileNameLen) {
                    lastFlag = MessageFlag.FileNameEndFlag
                    fileName = String(parseList.toByteArray(), 0, fileNameLen)
                    parseList.clear()
                    continue
                }
            }
            if (lastFlag == MessageFlag.FileNameEndFlag) { // 报尾校验
                if (parseList == MessageFlagByte.TailFlag) {
                    lastFlag = MessageFlag.TailFlag
                    valid = true
                    parseList.clear()
                    continue
                }
            }
        }
        if (valid) {
            if (fileName.isNotBlank()) {
                onFileName.invoke(fileName)
            }
        }
    }
}

fun messageLenIntToByte(len:Int):List<Byte> {
    val byteArray = arrayListOf<Byte>()
    val high = len shr 8
    val low = len and 0xff
    byteArray.add(high.toByte())
    byteArray.add(low.toByte())
    return byteArray
}
fun messageLenByteToInt(bytes: List<Byte>): Int {
    val high = bytes[0].toUByte()
    val low = bytes[1].toUByte()
    return (high.toInt() shl 8) + low.toInt()
}

fun log(text:String) {
    Log.d("FileTransferManager=", text)
}